/******************************************************************************
*	cmSem.c	Code file of CM Task Module.
*
*	coypright (C) 2009 Ding Lixing
*
******************************************************************************/

#include "cm.h"

static int semPrePost(cmOBJ *obj, void *param)
{
    cmSEMDATA *data = (cmSEMDATA *)(obj->data);

    (void)param;
    if(data->v < data->vMax){
        data->v++;
        return 0;
    }else{
        return CM_ERR_SemOverflow;
    }
}

static int semPrePend(cmOBJ *obj, void *param)
{
    cmSEMDATA *data = (cmSEMDATA *)(obj->data);

    (void)param;
    if(data->v < 1){
        return CM_ERR_SemExhausted;
    }else{
        data->v--;
        return 0;
    }
}

int cmSemInit(cmSEM *sem, unsigned int opt, int v,int vMax)
{
    if((opt & ~CM_OP_MASK) || (v < 0) || (v > vMax)){
        return CM_ERR_InvalidArgument;
    }
    
    sem->data.v = v;
    sem->data.vMax = vMax;

    return cmTaskObjInit(&sem->obj, CM_OBJ_SEM, opt, semPrePost, semPrePend, (void *)&sem->data);
}

int cmSemValueQuery(cmSEM *sem)
{
    int v;
    vmINTKEY key;

    key = vmIntLock();
    v = sem->data.v;
    vmIntUnlock(key);

    return v;
}

int cmSemGive(cmSEM *sem)
{
    return cmTaskObjPost(&sem->obj, (void *)0);
}

int cmSemTake(cmSEM *sem, unsigned int tout)
{
    return cmTaskObjPend(&sem->obj, tout, (void *)0);
}

